Golang

您所在的位置:网站首页 golang rpc 数量太多 Golang

Golang

2023-10-27 11:57| 来源: 网络整理| 查看: 265

我们常用的序列化和反序列化协议有XML, JSON, 以及有些语言所特有的工具比如PHP的serialize。

各个工具都有其特点,比如JSON使用广泛,占用字节较小,但是json串的序列化反序列化效率比较低;而XML虽然解析比较快,但是占用字节较多,太多冗余的字符。那么有没有一种跨语言的不仅占用字节少,而且效率还高的协议呢?

protobuf就是一个比较好的选择。

golang使用protobuf需要先安装 protoc 工具和 protoc-gen-go 代码生成器。

一般我们使用 protoc + protoc-gen-go + proto文件来生成代码。

安装方法:https://blog.csdn.net/raoxiaoya/article/details/109496431

proto语法目前最新版本是proto3。

protobuf 语法:https://protobuf.dev/programming-guides/proto3/

引入其他proto:import "protos/other.proto";

定义结构体

// Person: struct message Person { string name = 1; int64 age = 2; }

定义数组/集合

// persons: []*Person message SliceParam { repeated Person persons = 1; }

定义map

// personInfo: map[string]*Person message MapParam { map personInfo = 1; }

编写 message.proto 文件,在里面定义一个 OrderRequest 结构:

syntax = "proto3"; package message; //订单请求参数 message OrderRequest { string orderId = 1; int64 timeStamp = 2; }

这个是protobuf的语法,通过 protoc 工具可以生成指定语言的数据结构定义。

执行命令

protoc ./message.proto --go_out=./ WARNING: Missing 'go_package' option in "message.proto", please specify it with the full Go package path as a future release of protoc-gen-go will require this be specified.

但是文件还是生产成功了

解决: 在syntax下面添加option信息

option go_package = "aaa;bbb"; aaa 表示生成的go文件的存放地址,会自动生成目录的。 bbb 表示生成的go文件所属的包名

默认是当前目录下的message包。

修改 proto 文件:

syntax = "proto3"; option go_package = "./pbs;message"; package message; //订单请求参数 message OrderRequest { string orderId = 1; int64 timeStamp = 2; }

再次运行 protoc 命令

就能看到生成了 pbs/message.pb.go 文件,内容付在最后。

文件中有一个与 message OrderRequest 结构对应的go结构体:

type OrderRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields OrderId string `protobuf:"bytes,1,opt,name=orderId,proto3" json:"orderId,omitempty"` TimeStamp int64 `protobuf:"varint,2,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"` }

这就是经过protobuf转换后的数据结构,我们直接调用即可。

从结构可以看出,我们定义时写的是小写字母开头(orderId),转换后为大写开头(OrderId),同时 json 标签不变,注意,proto3提供的 json_name 选项只会修改 protobuf 标签中的 json 字段,而不是外面用来输出的 json 标签。如下:

message OrderRequest { string orderId = 1 [json_name="order_id"]; int64 timeStamp = 2; }

效果是

type OrderRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields OrderId string `protobuf:"bytes,1,opt,name=orderId,json=order_id,proto3" json:"orderId,omitempty"` TimeStamp int64 `protobuf:"varint,2,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"` }

那么,有什么办法呢,可以研究一下 https://github.com/gogo/protobuf

这个文件不需要编辑,在其他地方引用。

接下来将使用两个示例对比json和protobuf在字节占用上的差距。

package main import ( "encoding/json" "fmt" "time" "demo1/go-protobuf/pbs" "github.com/golang/protobuf/proto" ) func main() { Test() fmt.Println("--------------------------------------") Test1() } func Test1() { timeStamp := time.Now().Unix() request := &message.OrderRequest{OrderId: "201907310001", TimeStamp: timeStamp} data, _ := proto.Marshal(request) fmt.Println(string(data)) fmt.Println(len(data)) fmt.Println(proto.Size(request)) fmt.Printf("%T\n", data) msgEntity := message.OrderRequest{} proto.Unmarshal(data, &msgEntity) fmt.Println(proto.Size(&msgEntity)) fmt.Println(msgEntity) } func Test() { timeStamp := time.Now().Unix() request := message.OrderRequest{OrderId: "201907310001", TimeStamp: timeStamp} data, _ := json.Marshal(request) fmt.Println(string(data)) fmt.Println(len(data)) fmt.Printf("%T\n", data) }

打印信息:

{"orderId":"201907310001","timeStamp":1604539977} 49 []uint8 -------------------------------------- 201907310001ɬ��║ 20 20 []uint8 20 {{{} [] [] 0xc00005e500} 20 [] 201907310001 1604539977}

可以看出,使用这个结构来

type OrderRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields OrderId string `protobuf:"bytes,1,opt,name=orderId,proto3" json:"orderId,omitempty"` TimeStamp int64 `protobuf:"varint,2,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"` }

来代替我们普通的结构

type OrderRequest struct { OrderId string TimeStamp int64 }

同时,配合使用 github.com/golang/protobuf/proto包的序列化反序列化操作,才是protobuf的应用。使用 json 来序列化和反序列化 message.OrderRequest 对象并没有什么效果。

要知道json比XML本来就小不少,而protobuf比json还要小,有数据显示protobuf对比XML 小 3 ~ 10 倍 快 20 ~ 100 倍

关于protobuf的协议参考说明,网上非常多,可自行查阅。

message.pb.go 文件内容:

// Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 // protoc v3.13.0 // source: message.proto package message import ( proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // This is a compile-time assertion that a sufficiently up-to-date version // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 //订单请求参数 type OrderRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields OrderId string `protobuf:"bytes,1,opt,name=orderId,proto3" json:"orderId,omitempty"` TimeStamp int64 `protobuf:"varint,2,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"` } func (x *OrderRequest) Reset() { *x = OrderRequest{} if protoimpl.UnsafeEnabled { mi := &file_message_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *OrderRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*OrderRequest) ProtoMessage() {} func (x *OrderRequest) ProtoReflect() protoreflect.Message { mi := &file_message_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use OrderRequest.ProtoReflect.Descriptor instead. func (*OrderRequest) Descriptor() ([]byte, []int) { return file_message_proto_rawDescGZIP(), []int{0} } func (x *OrderRequest) GetOrderId() string { if x != nil { return x.OrderId } return "" } func (x *OrderRequest) GetTimeStamp() int64 { if x != nil { return x.TimeStamp } return 0 } var File_message_proto protoreflect.FileDescriptor var file_message_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x46, 0x0a, 0x0c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x70, 0x62, 0x73, 0x3b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_message_proto_rawDescOnce sync.Once file_message_proto_rawDescData = file_message_proto_rawDesc ) func file_message_proto_rawDescGZIP() []byte { file_message_proto_rawDescOnce.Do(func() { file_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_message_proto_rawDescData) }) return file_message_proto_rawDescData } var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_message_proto_goTypes = []interface{}{ (*OrderRequest)(nil), // 0: message.OrderRequest } var file_message_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_message_proto_init() } func file_message_proto_init() { if File_message_proto != nil { return } if !protoimpl.UnsafeEnabled { file_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*OrderRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_message_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_message_proto_goTypes, DependencyIndexes: file_message_proto_depIdxs, MessageInfos: file_message_proto_msgTypes, }.Build() File_message_proto = out.File file_message_proto_rawDesc = nil file_message_proto_goTypes = nil file_message_proto_depIdxs = nil }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3